// Volumetic.cpp: implementation of the Volumetic class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Volumetic.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

PFACECONECTIVITYDATA CreateConectivityData( DWORD dwFacesCount, LPBYTE pVertices, LPWORD pIndices, DWORD dwStride )
{
	PFACECONECTIVITYDATA	pCCData = new FACECONECTIVITYDATA[dwFacesCount];

	for( DWORD i = 0 ; i < dwFacesCount ; i++ )
	{
		pCCData[i].m_pdwEdge[0] = 0xffffffff;
		pCCData[i].m_pdwEdge[1] = 0xffffffff;
		pCCData[i].m_pdwEdge[2] = 0xffffffff;

		for( DWORD j = 0 ; j < dwFacesCount ; j++ )
		{
			if( i == j )
				continue;

			// checking each edge connection
			for( DWORD k = 0 ; k < 3 ; k++ )
			{					
				for( DWORD l = 0 ; l < 3 ; l++ )			
					if( ( pIndices[3*i+k] == pIndices[3*j+l] && pIndices[3*i+(k+1)%3] == pIndices[3*j+(1+1)%3] ) || ( pIndices[3*i+k] == pIndices[3*j+(l+1)%3] && pIndices[3*i+(k+1)%3] == pIndices[3*j+l] ) )
						pCCData[i].m_pdwEdge[k] = j;							
			}
		}


		// extract vertex pos from vertex data
		PFLOAT			vert1 = (PFLOAT)(pVertices + pIndices[3*i+0]*dwStride);
		PFLOAT			vert2 = (PFLOAT)(pVertices + pIndices[3*i+1]*dwStride);
		PFLOAT			vert3 = (PFLOAT)(pVertices + pIndices[3*i+2]*dwStride);		

		he3d_CVector	v1 = he3d_CVector( vert1[0], vert1[1], vert1[2] );
		he3d_CVector	v2 = he3d_CVector( vert2[0], vert2[1], vert2[2] );
		he3d_CVector	v3 = he3d_CVector( vert3[0], vert3[1], vert3[2] );

		pCCData[i].m_vN = Normalize( CrossProd( v2-v1, v3-v1 ) );
	}

	return pCCData;
}

BOOL CalculateConectivity( CSimpleMesh* mesh, PFACECONECTIVITYDATA& ppfcd )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;

	mesh->LockMesh( &pVertices, (LPBYTE*)&pIndices );
	ppfcd = CreateConectivityData( mesh->GetFacesCount(), pVertices, pIndices, mesh->GetVertexStride() );
	mesh->UnlockMesh();

	return TRUE;
}

BOOL CalculateConectivity( CSimpleMesh& mesh, PFACECONECTIVITYDATA& ppfcd )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;

	mesh.LockMesh( &pVertices, (LPBYTE*)&pIndices );
	ppfcd = CreateConectivityData( mesh.GetFacesCount(), pVertices, pIndices, mesh.GetVertexStride() );
	mesh.UnlockMesh();

	return TRUE;
}

BOOL CalculateConectivity( DWORD dwFacesCount, PDIRECT3DVERTEXBUFFER8 pvb, PDIRECT3DINDEXBUFFER8 pib, PFACECONECTIVITYDATA& ppfcd )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;

	D3DVERTEXBUFFER_DESC	vbdesc;

	pvb->GetDesc( &vbdesc );
	pvb->Lock( 0, 0, &pVertices, 0 );
	pib->Lock( 0, 0, (LPBYTE*)&pIndices, 0 );
	ppfcd = CreateConectivityData( dwFacesCount, pVertices, pIndices, D3DXGetFVFVertexSize( vbdesc.FVF ) );
	pvb->Unlock();
	pib->Unlock();

	return TRUE;
}

BOOL CalculateConectivity( DWORD dwFacesCount, PDIRECT3DVERTEXBUFFER8 pvb, PDIRECT3DINDEXBUFFER8 pib, DWORD dwStride, PFACECONECTIVITYDATA& ppfcd )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;	
	
	pvb->Lock( 0, 0, &pVertices, 0 );
	pib->Lock( 0, 0, (LPBYTE*)&pIndices, 0 );
	ppfcd = CreateConectivityData( dwFacesCount, pVertices, pIndices, dwStride );
	pvb->Unlock();
	pib->Unlock();

	return TRUE;
}

BOOL CreateShiluette( DWORD dwFacesCount, LPBYTE pVertices, LPWORD pIndices, DWORD dwStride, PFACECONECTIVITYDATA pfcd, he3d_CMatrix mtxTrn, he3d_CMatrix mtxView, DWORD& dwShiluetteCount, he3d_CVector* pvShiluette )
{
	// at first calculate visibility
	he3d_CMatrix			mtx = mtxTrn*mtxView;
	DWORD					i;
	he3d_CVector			v;	

	for( i = 0 ; i < dwFacesCount ; i++ )
	{
		v = pfcd[i].m_vN*mtx;

		if( v.z <= 0 )
			pfcd[i].m_bVisible = FALSE;
		else
			pfcd[i].m_bVisible = TRUE;
	}

	for( i = 0, dwShiluetteCount = 0 ; i < dwFacesCount ; i++ )
	{	
		if( !pfcd[i].m_bVisible )
			continue;

		for( DWORD j = 0 ; j < 3 ; j++ )
		{		
			if( pfcd[i].m_pdwEdge[j] == 0xffffffff || !pfcd[pfcd[i].m_pdwEdge[j]].m_bVisible )
			{
				v = *((he3d_CVector*)(pVertices + pIndices[3*i+j]*dwStride));
				pvShiluette[dwShiluetteCount++] = v*mtxTrn;
				v = *((he3d_CVector*)(pVertices + dwStride*pIndices[3*i+(j+1)%3]));
				pvShiluette[dwShiluetteCount++] = v*mtxTrn;
			}
		}
	}

	return TRUE;
}

BOOL CreateShiluette( CSimpleMesh& mesh, PFACECONECTIVITYDATA pfcd, he3d_CMatrix& mtx, DWORD& dwShiluetteCount, he3d_CVector* pvShiluette )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;

	mesh.LockMesh( &pVertices, (LPBYTE*)&pIndices );
	CreateShiluette( mesh.GetFacesCount(), pVertices, pIndices, mesh.GetVertexStride(), pfcd, mtx, IdentMtx(), dwShiluetteCount, pvShiluette );
	mesh.UnlockMesh();

	return TRUE;
}

BOOL CreateShiluette( CSimpleMesh* mesh, PFACECONECTIVITYDATA pfcd, he3d_CMatrix& mtx, DWORD& dwShiluetteCount, he3d_CVector* pvShiluette )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;

	mesh->LockMesh( &pVertices, (LPBYTE*)&pIndices );
	CreateShiluette( mesh->GetFacesCount(), pVertices, pIndices, mesh->GetVertexStride(), pfcd, mtx, IdentMtx(), dwShiluetteCount, pvShiluette );
	mesh->UnlockMesh();

	return TRUE;
}

BOOL CreateShiluette( DWORD dwFacesCount, PDIRECT3DVERTEXBUFFER8 pvb, PDIRECT3DINDEXBUFFER8 pib, PFACECONECTIVITYDATA pfcd, he3d_CMatrix& mtx, DWORD& dwShiluetteCount, he3d_CVector* pvShiluette )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;
	D3DVERTEXBUFFER_DESC	vbdesc;

	pvb->GetDesc( &vbdesc );

	pvb->Lock( 0, 0, &pVertices, 0 );
	pib->Lock( 0, 0, (LPBYTE*)&pIndices, 0 );
	CreateShiluette( dwFacesCount, pVertices, pIndices, D3DXGetFVFVertexSize( vbdesc.FVF ), pfcd, mtx, IdentMtx(), dwShiluetteCount, pvShiluette );
	pvb->Unlock();
	pib->Unlock();

	return TRUE;
}

BOOL CreateShiluette( DWORD dwFacesCount, PDIRECT3DVERTEXBUFFER8 pvb, PDIRECT3DINDEXBUFFER8 pib, DWORD dwStride, PFACECONECTIVITYDATA pfcd, he3d_CMatrix& mtx, DWORD& dwShiluetteCount, he3d_CVector* pvShiluette )
{
	LPBYTE					pVertices;
	LPWORD					pIndices;		

	pvb->Lock( 0, 0, &pVertices, 0 );
	pib->Lock( 0, 0, (LPBYTE*)&pIndices, 0 );
	CreateShiluette( dwFacesCount, pVertices, pIndices, dwStride, pfcd, mtx, IdentMtx(), dwShiluetteCount, pvShiluette );
	pvb->Unlock();
	pib->Unlock();

	return TRUE;
}

BOOL CreateVolumeFromShiluette( DWORD dwShiluetteCount, he3d_CVector* pvShiluette, he3d_CVector& vPoint, DWORD dwStride, LPBYTE pVertices, FLOAT length )
{
	he3d_CVector*			pvUpShiluette = new he3d_CVector[dwShiluetteCount];		
	DWORD					i;

	for( i = 0 ; i < dwShiluetteCount ; i++ )	
		pvUpShiluette[i] = length*Normalize( pvShiluette[i] - vPoint ) + pvShiluette[i];	

	for( i = 0 ; i < dwShiluetteCount ; i+=2 )
	{
		*((he3d_CVector*)pVertices) = pvShiluette[i];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;

		*((he3d_CVector*)pVertices) = pvShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;
	}

	return TRUE;
}

BOOL CreateParallelVolumeFromShiluette( DWORD dwShiluetteCount, he3d_CVector* pvShiluette, he3d_CVector& vDir, DWORD dwStride, LPBYTE pVertices, FLOAT length )
{
	he3d_CVector*			pvUpShiluette = new he3d_CVector[dwShiluetteCount];		
	DWORD					i;

	for( i = 0 ; i < dwShiluetteCount ; i++ )	
		pvUpShiluette[i] = length*vDir + pvShiluette[i];	

	for( i = 0 ; i < dwShiluetteCount ; i+=2 )
	{
		*((he3d_CVector*)pVertices) = pvShiluette[i];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;

		*((he3d_CVector*)pVertices) = pvShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i+1];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;
	}

	delete pvUpShiluette;

	return TRUE;
}

BOOL CreateVolumeFromShiluetteStrip( DWORD dwShiluetteCount, he3d_CVector* pvShiluette, he3d_CVector& vPoint, DWORD dwStride, LPBYTE pVertices, FLOAT length )
{
	he3d_CVector*			pvUpShiluette = new he3d_CVector[dwShiluetteCount];		
	DWORD					i;

	for( i = 0 ; i < dwShiluetteCount ; i++ )	
		pvUpShiluette[i] = length*Normalize( pvShiluette[i] - vPoint ) + pvShiluette[i];	

	for( i = 0 ; i < dwShiluetteCount ; i++ )
	{
		*((he3d_CVector*)pVertices) = pvShiluette[i];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;

		*((he3d_CVector*)pVertices) = pvShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;
	}

	return TRUE;
}
	 
BOOL CreateParallelVolumeFromShiluetteStrip( DWORD dwShiluetteCount, he3d_CVector* pvShiluette, he3d_CVector& vDir, DWORD dwStride, LPBYTE pVertices, FLOAT length )
{
	he3d_CVector*			pvUpShiluette = new he3d_CVector[dwShiluetteCount];		
	DWORD					i;

	for( i = 0 ; i < dwShiluetteCount ; i++ )	
		pvUpShiluette[i] = length*vDir + pvShiluette[i];	

	for( i = 0 ; i < dwShiluetteCount ; i++ )
	{
		*((he3d_CVector*)pVertices) = pvShiluette[i];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;

		*((he3d_CVector*)pVertices) = pvShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[(i+1)%dwShiluetteCount];
		pVertices += dwStride;
		*((he3d_CVector*)pVertices) = pvUpShiluette[i];
		pVertices += dwStride;
	}

	delete pvUpShiluette;

	return TRUE;
}
